<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        body {
            margin: 10px auto;
        }

        a {
            display: block;
            position: absolute;
            left: 0;
            top: 0;
            text-decoration: none;
            color: inherit;
        }

        .container {
            position: relative;
            margin: 20px;
        }

        .move {
            display: none;
            position: absolute;
            left: 0;
            top: 0;
            box-shadow: 0 0 5px #ccc;
            z-index: 2;
            border-radius: 3px;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div class="container">
        <a href="https://juejin.cn/user/3936714046056088/posts" class="move">
            <img src="https://i0.hdslb.com/bfs/vc/c13315f4c4195b342fd0d2795fd6c8b090a717bf.jpg" alt="">
        </a>
        <a href="https://juejin.cn/user/3936714046056088/posts" class="static-img">
            <img src="https://i0.hdslb.com/bfs/vc/c13315f4c4195b342fd0d2795fd6c8b090a717bf.jpg" alt="">
        </a>
    </div>

    <script type="text/javascript">
        const config = {
            w: 640,
            h: 360,
            moveHeight: 60,
            moveWidth: 60,
            scale: 2.2
        };


        const container = document.querySelector('.container'),
            staticImg = container.querySelector('.static-img img'),
            move = container.querySelector('.move'),
            moveImg = move.querySelector('img');

        init();
        const { left: _left, top: _top } = getRect(container),
            halfWidth = getStyle(move, 'width') / 2,
            halfHeight = getStyle(move, 'height') / 2;


        function init() {
            setSize();
            bindEvent();
        }

        function bindEvent() {
            container.addEventListener('mouseover', setVisible);
            container.addEventListener('mouseout', setVisible);

            container.addEventListener('mousemove', (e) => {
                const { clientX, clientY } = e;
                const x = clientX - _left - halfWidth,
                    y = clientY - _top - halfHeight;

                if (judge(x, y)) {
                    return;
                }

                move.style.transform = `translate(${x}px, ${y}px) scale(${config.scale})`;
                moveImg.style.transform = `translate(${-x}px, ${-y}px)`;
            });
        }

        function judge(x, y) {
            return (
                x < -halfWidth || y < -halfHeight ||
                x > container.offsetWidth - halfWidth ||
                y > container.offsetHeight - halfHeight
            );
        }

        function getRect(el) {
            return el.getBoundingClientRect();
        }

        function getStyle(el, key) {
            return parseInt(getComputedStyle(el)[key]);
        }

        function setSize() {
            staticImg.style.width = config.w + 'px';
            staticImg.style.height = config.h + 'px';
            container.style.height = config.h + 'px';
            container.style.width = config.w + 'px';

            move.style.width = config.moveWidth + 'px';
            move.style.height = config.moveHeight + 'px';
            move.style.transform = `scale(${config.scale})`;

            moveImg.style.width = config.w + 'px';
            moveImg.style.height = config.h + 'px';
        }

        function setVisible() {
            const flag = getComputedStyle(move).display === 'none'
                ? 'block'
                : 'none';

            move.style.display = flag;
        }
    </script>
</body>

</html>